package com.example.lock;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionCommunication {
    public static void main(String[] args) {
        final Business business = new Business();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 1; i <= 50; i++) {
                            business.sub(i);
                        }
                    }
                }
        ).start();

        for (int i = 1; i <= 50; i++) {
            business.main(i);
        }
    }
}

//经验：要用到共同数据(包括同步锁)或共同算法的若干个方法应该归在同一个类身上，
// 这种设计正好体现了高类聚和程序的健壮性
//锁是上在代表要操作的资源的类的内部方法中，而不是线程代码中！
class Business {
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    private boolean bShouldSub = true;

    public void sub(int i) {
        //if(!bShouldSub){
        //因为在没有通知时的也会唤醒，用while防止不必要的唤醒
        lock.lock();
        try {
            while (!bShouldSub) {
                try {
                    condition.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            for (int j = 1; j < 10; j++) {
                System.out.println("sub thread sequence of" + j + "loop of" + i);
            }
            bShouldSub = false;
            condition.signal();
        } finally {
            lock.unlock();
        }
    }

    public void main(int i) {
        lock.lock();
        try {

            while (bShouldSub) {
                try {
                    condition.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            for (int j = 1; j <= 10; j++) {
                System.out.println("main thread sequence of" + j + "loop of" + i);
            }
            bShouldSub = true;
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}

